package ntd.util.frame.javacv.tool;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.log.StaticLog;
import ntd.util.UtilCatch;
import ntd.util.config.common.exception.ComException;
import ntd.util.util.ToolDuration;
import org.bytedeco.javacv.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class ToolFFmpeg {

    private static String commandPath = "C:\\Users\\lwj\\Downloads\\ffmpeg-2022-08-31-git-319e8a49b5-essentials_build\\bin\\ffmpeg.exe";

    /**
     * 获取第一秒第一帧的缩略图 -- （cmd(windows): ffmpeg.exe -ss 00:00:01 -y -i test1.mp4 -vframes 1 new.jpg）
     *
     * @param videoInputPath  视频文件路径（输入）
     * @param coverOutputPath 缩略图输出路径
     * @throws IOException
     */
    public static void getVideoCover(String videoInputPath, String coverOutputPath) throws IOException {
        // 构建命令
        List<String> command = new ArrayList<>();
        command.add(commandPath);
        command.add("-ss");
        command.add("00:00:01");
        command.add("-y");
        command.add("-i");
        command.add(videoInputPath);
        command.add("-vframes");
        command.add("1");
        command.add(coverOutputPath);
        // 执行操作
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();
        InputStream errorStream = process.getErrorStream();
        InputStreamReader isr = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        if (br != null) {
            br.close();
        }
        if (isr != null) {
            isr.close();
        }
        if (errorStream != null) {
            errorStream.close();
        }
    }

    /**
     * 简易视频处理 -- （cmd(windows): ffmpeg.exe -i test1.mp4 newVideo.avi）
     *
     * @param videoInputPath  视频文件路径（输入）
     * @param videoOutputPath 转换完成的文件路径（输出）
     * @throws IOException
     */
    public static void videoConvert(String videoInputPath, String videoOutputPath) throws IOException {
        // 构建命令
        List<String> command = new ArrayList<>();
        command.add(commandPath);
        command.add("-i");
        command.add(videoInputPath);
        command.add(videoOutputPath);
        // 执行操作
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();
        InputStream errorStream = process.getErrorStream();
        InputStreamReader isr = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        if (br != null) {
            br.close();
        }
        if (isr != null) {
            isr.close();
        }
        if (errorStream != null) {
            errorStream.close();
        }
    }

    /**
     * 音视频合并，视频结束，音频结束 -- （cmd(windows): ffmpeg.exe -i test2.mp3 -i test1.mp4 -t 10 -y newVideo.mp4）
     *
     * @param audioInputPath  音频文件路径（输入）
     * @param videoInputPath  视频文件路径（输入）
     * @param time            文件时长
     * @param videoOutputPath 转换完成的文件路径（输出）
     * @throws IOException
     */
    public static void audioVideoMerge(String audioInputPath, String videoInputPath, double time, String videoOutputPath) throws IOException {
        // 构建命令
        List<String> command = new ArrayList<>();
        command.add(commandPath);
        command.add("-i");
        command.add(audioInputPath);
        command.add("-i");
        command.add(videoInputPath);
        command.add("-t");
        command.add(String.valueOf(time));
        command.add("-y");
        command.add(videoOutputPath);

        // 执行操作
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();
        InputStream errorStream = process.getErrorStream();
        InputStreamReader isr = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        if (br != null) {
            br.close();
        }
        if (isr != null) {
            isr.close();
        }
        if (errorStream != null) {
            errorStream.close();
        }
    }

    public static FFmpegFrameGrabber createGrabber(String rtsp) {
        // 获取视频源
        try {
            FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(rtsp);
            grabber.setOption("rtsp_transport", "tcp");
//            grabber.setOption("thread_queue_size", "512");
            // 设置分析的最长时间
            grabber.setOption("analyzeduration", "10000");
            // 设置读取的最大数据，单位：字节
            grabber.setOption("probesize", "1024");

            // 设置采集器构造超时时间(单位微秒，1秒=1000000微秒)
//            grabber.setOption("stimeout", "2000000");


//             grabber.setOption("--enable-decoder", "h265");
//             grabber.setOption("--enable-parser", "h265");
            // grabber.setOption("--enable-bsf", "extract_extradata");
            // grabber.setOption("--enable-muxer", "flv");

            // 设置帧率
            grabber.setFrameRate(30);
            // 设置获取的视频宽度
//            grabber.setImageWidth(1280);
            // 设置获取的视频高度
//            grabber.setImageHeight(720);
            // 设置视频bit率
            grabber.setVideoBitrate(3000000);
            return grabber;
        } catch (FrameGrabber.Exception e) {
            StaticLog.error("create rtsp FFmpegFrameGrabber exception: ", e);
            return null;
        }
    }

    public static byte[] getKeyImg(String rtspUrl) {
        FFmpegFrameGrabber grabber = createGrabber(rtspUrl);

        return UtilCatch.tryCatch(() -> ToolDuration.duration(() -> {
            grabber.start();
            //关键帧
//            Frame frame = grabber.grabKeyFrame();
            grabber.setFrameNumber(100);
            Frame frame = grabber.grabImage();
            if (ObjectUtil.isNotNull(frame)) {
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                return UtilCatch.tryCatch(() -> {
                    Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();
                    BufferedImage bufferedImage = java2DFrameConverter.getBufferedImage(frame);
                    ImageIO.write(bufferedImage, "jpg", os);
                    new CanvasFrame(rtspUrl).showImage(frame);
                    return os.toByteArray();
                }, () -> UtilCatch.tryCatchNoRes(() -> {
                    os.close();
                    frame.close();
                }));
            }
            throw new ComException("[{}] - 关键帧获取失败", rtspUrl);
        }, "海康获取关键帧"), () -> UtilCatch.tryCatchNoRes(() -> {
            assert grabber != null;
            grabber.stop();
            grabber.release();
            grabber.close();
        }));
    }

    public static void main(String[] args) {
    }
}
